﻿/*
License of uGUI
----------------------------------------------------------------------------------
The MIT License (MIT)

Copyright (c) 2014, Unity Technologies

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
----------------------------------------------------------------------------------
*/
using UnityEngine;
using UnityEditor;
using UnityEngine.EventSystems;
using UnityEngine.UI;

namespace Picker
{	
	//namespace UnityEditor.UI
	//{
		/// <summary>
		/// This script adds the UI menu options to the Unity Editor.
		/// </summary>
		
		static internal class MenuOptions
		{
			public const string kUILayerName = "UI";
			public const float  kWidth       = 160f;
			public const float  kThickHeight = 30f;
			public const float  kThinHeight  = 20f;
			public const string kStandardSpritePath           = "UI/Skin/UISprite.psd";
			public const string kBackgroundSpriteResourcePath = "UI/Skin/Background.psd";
			public const string kInputFieldBackgroundPath     = "UI/Skin/InputFieldBackground.psd";
			public const string kKnobPath                     = "UI/Skin/Knob.psd";
			public const string kCheckmarkPath                = "UI/Skin/Checkmark.psd";
			
			public static Vector2 s_ThickGUIElementSize    = new Vector2(kWidth, kThickHeight);
			public static Vector2 s_ThinGUIElementSize     = new Vector2(kWidth, kThinHeight);
			public static Vector2 s_ImageGUIElementSize    = new Vector2(100f, 100f);
			public static Color   s_DefaultSelectableColor = new Color(1f, 1f, 1f, 1f);
			public static Color   s_PanelColor             = new Color(1f, 1f, 1f, 0.392f);
			public static Color   s_TextColor              = new Color(50f / 255f, 50f / 255f, 50f / 255f, 1f);
			
			public static void SetPositionVisibleinSceneView(RectTransform canvasRTransform, RectTransform itemTransform)
			{
				// Find the best scene view
				SceneView sceneView = SceneView.lastActiveSceneView;
				if (sceneView == null && SceneView.sceneViews.Count > 0)
					sceneView = SceneView.sceneViews[0] as SceneView;
				
				// Couldn't find a SceneView. Don't set position.
				if (sceneView == null || sceneView.camera == null)
					return;
				
				// Create world space Plane from canvas position.
				Vector2 localPlanePosition;
				Camera camera = sceneView.camera;
				Vector3 position = Vector3.zero;
				if (RectTransformUtility.ScreenPointToLocalPointInRectangle(canvasRTransform, new Vector2(camera.pixelWidth / 2, camera.pixelHeight / 2), camera, out localPlanePosition))
				{
					// Adjust for canvas pivot
					localPlanePosition.x = localPlanePosition.x + canvasRTransform.sizeDelta.x * canvasRTransform.pivot.x;
					localPlanePosition.y = localPlanePosition.y + canvasRTransform.sizeDelta.y * canvasRTransform.pivot.y;
					
					localPlanePosition.x = Mathf.Clamp(localPlanePosition.x, 0, canvasRTransform.sizeDelta.x);
					localPlanePosition.y = Mathf.Clamp(localPlanePosition.y, 0, canvasRTransform.sizeDelta.y);
					
					// Adjust for anchoring
					position.x = localPlanePosition.x - canvasRTransform.sizeDelta.x * itemTransform.anchorMin.x;
					position.y = localPlanePosition.y - canvasRTransform.sizeDelta.y * itemTransform.anchorMin.y;
					
					Vector3 minLocalPosition;
					minLocalPosition.x = canvasRTransform.sizeDelta.x * (0 - canvasRTransform.pivot.x) + itemTransform.sizeDelta.x * itemTransform.pivot.x;
					minLocalPosition.y = canvasRTransform.sizeDelta.y * (0 - canvasRTransform.pivot.y) + itemTransform.sizeDelta.y * itemTransform.pivot.y;
					
					Vector3 maxLocalPosition;
					maxLocalPosition.x = canvasRTransform.sizeDelta.x * (1 - canvasRTransform.pivot.x) - itemTransform.sizeDelta.x * itemTransform.pivot.x;
					maxLocalPosition.y = canvasRTransform.sizeDelta.y * (1 - canvasRTransform.pivot.y) - itemTransform.sizeDelta.y * itemTransform.pivot.y;
					
					position.x = Mathf.Clamp(position.x, minLocalPosition.x, maxLocalPosition.x);
					position.y = Mathf.Clamp(position.y, minLocalPosition.y, maxLocalPosition.y);
				}
				
				itemTransform.anchoredPosition = position;
				itemTransform.localRotation = Quaternion.identity;
				itemTransform.localScale = Vector3.one;
			}
			
			public static GameObject CreateUIElementRoot(string name, MenuCommand menuCommand, Vector2 size)
			{
				GameObject parent = menuCommand.context as GameObject;
				if (parent == null || parent.GetComponentInParent<Canvas>() == null)
				{
					parent = GetOrCreateCanvasGameObject();
				}
				GameObject child = new GameObject(name);
				
				Undo.RegisterCreatedObjectUndo(child, "Create " + name);
				Undo.SetTransformParent(child.transform, parent.transform, "Parent " + child.name);
				GameObjectUtility.SetParentAndAlign(child, parent);
				
				RectTransform rectTransform = child.AddComponent<RectTransform>();
				rectTransform.sizeDelta = size;
				if (parent != menuCommand.context) // not a context click, so center in sceneview
				{
					SetPositionVisibleinSceneView(parent.GetComponent<RectTransform>(), rectTransform);
				}
				Selection.activeGameObject = child;
				return child;
			}
			
			//[MenuItem("GameObject/UI/Panel", false, 2000)]
			static public void AddPanel(MenuCommand menuCommand)
			{
				GameObject panelRoot = CreateUIElementRoot("Panel", menuCommand, s_ThickGUIElementSize);
				
				// Set RectTransform to stretch
				RectTransform rectTransform = panelRoot.GetComponent<RectTransform>();
				rectTransform.anchorMin = Vector2.zero;
				rectTransform.anchorMax = Vector2.one;
				rectTransform.anchoredPosition = Vector2.zero;
				rectTransform.sizeDelta = Vector2.zero;
				
				Image image = panelRoot.AddComponent<Image>();
				image.sprite = AssetDatabase.GetBuiltinExtraResource<Sprite>(kBackgroundSpriteResourcePath);
				image.type = Image.Type.Sliced;
				image.color = s_PanelColor;
			}
			
			//[MenuItem("GameObject/UI/Button", false, 2001)]
			static public void AddButton(MenuCommand menuCommand)
			{
				GameObject buttonRoot = CreateUIElementRoot("Button", menuCommand, s_ThickGUIElementSize);
				
				GameObject childText = new GameObject("Text");
				GameObjectUtility.SetParentAndAlign(childText, buttonRoot);
				
				Image image = buttonRoot.AddComponent<Image>();
				image.sprite = AssetDatabase.GetBuiltinExtraResource<Sprite>(kStandardSpritePath);
				image.type = Image.Type.Sliced;
				image.color = s_DefaultSelectableColor;
				
				UnityEngine.UI.Button bt = buttonRoot.AddComponent<UnityEngine.UI.Button>();
				SetDefaultColorTransitionValues(bt);
				
				Text text = childText.AddComponent<Text>();
				text.text = "Button";
				text.alignment = TextAnchor.MiddleCenter;
				SetDefaultTextValues(text);
				
				RectTransform textRectTransform = childText.GetComponent<RectTransform>();
				textRectTransform.anchorMin = Vector2.zero;
				textRectTransform.anchorMax = Vector2.one;
				textRectTransform.sizeDelta = Vector2.zero;
			}
			
			//[MenuItem("GameObject/UI/Text", false, 2002)]
			static public void AddText(MenuCommand menuCommand)
			{
				GameObject go = CreateUIElementRoot("Text", menuCommand, s_ThickGUIElementSize);
				
				Text lbl = go.AddComponent<Text>();
				lbl.text = "New Text";
				SetDefaultTextValues(lbl);
			}
			
			public static void SetDefaultTextValues(Text lbl)
			{
				// Set text values we want across UI elements in default controls.
				// Don't set values which are the same as the default values for the Text component,
				// since there's no point in that, and it's good to keep them as consistent as possible.
				lbl.color = s_TextColor;
			}
			
			//[MenuItem("GameObject/UI/Image", false, 2003)]
			static public void AddImage(MenuCommand menuCommand)
			{
				GameObject go = CreateUIElementRoot("Image", menuCommand, s_ImageGUIElementSize);
				go.AddComponent<Image>();
			}
			
			//[MenuItem("GameObject/UI/RawImage", false, 2004)]
			static public void AddRawImage(MenuCommand menuCommand)
			{
				GameObject go = CreateUIElementRoot("RawImage", menuCommand, s_ImageGUIElementSize);
				go.AddComponent<RawImage>();
			}
			
			static GameObject CreateUIObject(string name, GameObject parent)
			{
				GameObject go = new GameObject(name);
				go.AddComponent<RectTransform>();
				GameObjectUtility.SetParentAndAlign(go, parent);
				return go;
			}
			
			//[MenuItem("GameObject/UI/Slider", false, 2006)]
			static public void AddSlider(MenuCommand menuCommand)
			{
				// Create GOs Hierarchy
				GameObject root = CreateUIElementRoot("Slider", menuCommand, s_ThinGUIElementSize);
				
				GameObject background = CreateUIObject("Background", root);
				GameObject fillArea = CreateUIObject("Fill Area", root);
				GameObject fill = CreateUIObject("Fill", fillArea);
				GameObject handleArea = CreateUIObject("Handle Slide Area", root);
				GameObject handle = CreateUIObject("Handle", handleArea);
				
				// Background
				Image backgroundImage = background.AddComponent<Image>();
				backgroundImage.sprite = AssetDatabase.GetBuiltinExtraResource<Sprite>(kBackgroundSpriteResourcePath);
				backgroundImage.type = Image.Type.Sliced;
				backgroundImage.color = s_DefaultSelectableColor;
				RectTransform backgroundRect = background.GetComponent<RectTransform>();
				backgroundRect.anchorMin = new Vector2(0, 0.25f);
				backgroundRect.anchorMax = new Vector2(1, 0.75f);
				backgroundRect.sizeDelta = new Vector2(0, 0);
				
				// Fill Area
				RectTransform fillAreaRect = fillArea.GetComponent<RectTransform>();
				fillAreaRect.anchorMin = new Vector2(0, 0.25f);
				fillAreaRect.anchorMax = new Vector2(1, 0.75f);
				fillAreaRect.anchoredPosition = new Vector2(-5, 0);
				fillAreaRect.sizeDelta = new Vector2(-20, 0);
				
				// Fill
				Image fillImage = fill.AddComponent<Image>();
				fillImage.sprite = AssetDatabase.GetBuiltinExtraResource<Sprite>(kStandardSpritePath);
				fillImage.type = Image.Type.Sliced;
				fillImage.color = s_DefaultSelectableColor;
				
				RectTransform fillRect = fill.GetComponent<RectTransform>();
				fillRect.sizeDelta = new Vector2(10, 0);
				
				// Handle Area
				RectTransform handleAreaRect = handleArea.GetComponent<RectTransform>();
				handleAreaRect.sizeDelta = new Vector2(-20, 0);
				handleAreaRect.anchorMin = new Vector2(0, 0);
				handleAreaRect.anchorMax = new Vector2(1, 1);
				
				// Handle
				Image handleImage = handle.AddComponent<Image>();
				handleImage.sprite = AssetDatabase.GetBuiltinExtraResource<Sprite>(kKnobPath);
				handleImage.color = s_DefaultSelectableColor;
				
				RectTransform handleRect = handle.GetComponent<RectTransform>();
				handleRect.sizeDelta = new Vector2(20, 0);
				
				// Setup slider component
				Slider slider = root.AddComponent<Slider>();
				slider.fillRect = fill.GetComponent<RectTransform>();
				slider.handleRect = handle.GetComponent<RectTransform>();
				slider.targetGraphic = handleImage;
				slider.direction = Slider.Direction.LeftToRight;
				SetDefaultColorTransitionValues(slider);
			}
			
			public static void SetDefaultColorTransitionValues(Selectable slider)
			{
				ColorBlock colors = slider.colors;
				colors.highlightedColor = new Color(0.882f, 0.882f, 0.882f);
				colors.pressedColor     = new Color(0.698f, 0.698f, 0.698f);
				colors.disabledColor    = new Color(0.521f, 0.521f, 0.521f);
			}
			
			//[MenuItem("GameObject/UI/Scrollbar", false, 2007)]
			static public void AddScrollbar(MenuCommand menuCommand)
			{
				// Create GOs Hierarchy
				GameObject scrollbarRoot = CreateUIElementRoot("Scrollbar", menuCommand, s_ThinGUIElementSize);
				
				GameObject sliderArea = CreateUIObject("Sliding Area", scrollbarRoot);
				GameObject handle = CreateUIObject("Handle", sliderArea);
				
				Image bgImage = scrollbarRoot.AddComponent<Image>();
				bgImage.sprite = AssetDatabase.GetBuiltinExtraResource<Sprite>(kBackgroundSpriteResourcePath);
				bgImage.type = Image.Type.Sliced;
				bgImage.color = s_DefaultSelectableColor;
				
				Image handleImage = handle.AddComponent<Image>();
				handleImage.sprite = AssetDatabase.GetBuiltinExtraResource<Sprite>(kStandardSpritePath);
				handleImage.type = Image.Type.Sliced;
				handleImage.color = s_DefaultSelectableColor;
				
				RectTransform sliderAreaRect = sliderArea.GetComponent<RectTransform>();
				sliderAreaRect.sizeDelta = new Vector2(-20, -20);
				sliderAreaRect.anchorMin = Vector2.zero;
				sliderAreaRect.anchorMax = Vector2.one;
				
				RectTransform handleRect = handle.GetComponent<RectTransform>();
				handleRect.sizeDelta = new Vector2(20, 20);
				
				Scrollbar scrollbar = scrollbarRoot.AddComponent<Scrollbar>();
				scrollbar.handleRect = handleRect;
				scrollbar.targetGraphic = handleImage;
				SetDefaultColorTransitionValues(scrollbar);
			}
			
			//[MenuItem("GameObject/UI/Toggle", false, 2008)]
			static public void AddToggle(MenuCommand menuCommand)
			{
				// Set up hierarchy
				GameObject toggleRoot = CreateUIElementRoot("Toggle", menuCommand, s_ThinGUIElementSize);
				
				GameObject background = CreateUIObject("Background", toggleRoot);
				GameObject checkmark = CreateUIObject("Checkmark", background);
				GameObject childLabel = CreateUIObject("Label", toggleRoot);
				
				// Set up components
				Toggle toggle = toggleRoot.AddComponent<Toggle>();
				toggle.isOn = true;
				
				Image bgImage = background.AddComponent<Image>();
				bgImage.sprite = AssetDatabase.GetBuiltinExtraResource<Sprite>(kStandardSpritePath);
				bgImage.type = Image.Type.Sliced;
				bgImage.color = s_DefaultSelectableColor;
				
				Image checkmarkImage = checkmark.AddComponent<Image>();
				checkmarkImage.sprite = AssetDatabase.GetBuiltinExtraResource<Sprite>(kCheckmarkPath);
				
				Text label = childLabel.AddComponent<Text>();
				label.text = "Toggle";
				SetDefaultTextValues(label);
				
				toggle.graphic = checkmarkImage;
				toggle.targetGraphic = bgImage;
				SetDefaultColorTransitionValues(toggle);
				
				RectTransform bgRect = background.GetComponent<RectTransform>();
				bgRect.anchorMin        = new Vector2(0f, 1f);
				bgRect.anchorMax        = new Vector2(0f, 1f);
				bgRect.anchoredPosition = new Vector2(10f, -10f);
				bgRect.sizeDelta        = new Vector2(kThinHeight, kThinHeight);
				
				RectTransform checkmarkRect = checkmark.GetComponent<RectTransform>();
				checkmarkRect.anchorMin = new Vector2(0.5f, 0.5f);
				checkmarkRect.anchorMax = new Vector2(0.5f, 0.5f);
				checkmarkRect.anchoredPosition = Vector2.zero;
				checkmarkRect.sizeDelta = new Vector2(20f, 20f);
				
				RectTransform labelRect = childLabel.GetComponent<RectTransform>();
				labelRect.anchorMin        = new Vector2(0f, 0f);
				labelRect.anchorMax        = new Vector2(1f, 1f);
				labelRect.offsetMin        = new Vector2(23f, 1f);
				labelRect.offsetMax        = new Vector2(-5f, -2f);
			}
			
			//[MenuItem("GameObject/UI/InputField", false, 2008)]
			public static void AddInputField(MenuCommand menuCommand)
			{
				GameObject root = CreateUIElementRoot("InputField", menuCommand, s_ThickGUIElementSize);
				
				GameObject childPlaceholder = CreateUIObject("Placeholder", root);
				GameObject childText = CreateUIObject("Text", root);
				
				Image image = root.AddComponent<Image>();
				image.sprite = AssetDatabase.GetBuiltinExtraResource<Sprite>(kInputFieldBackgroundPath);
				image.type = Image.Type.Sliced;
				image.color = s_DefaultSelectableColor;
				
				InputField inputField = root.AddComponent<InputField>();
				SetDefaultColorTransitionValues(inputField);
				
				Text text = childText.AddComponent<Text>();
				text.text = "";
				text.supportRichText = false;
				SetDefaultTextValues(text);
				
				Text placeholder = childPlaceholder.AddComponent<Text>();
				placeholder.text = "Enter text...";
				placeholder.fontStyle = FontStyle.Italic;
				// Make placeholder color half as opaque as normal text color.
				Color placeholderColor = text.color;
				placeholderColor.a *= 0.5f;
				placeholder.color = placeholderColor;
				
				RectTransform textRectTransform = childText.GetComponent<RectTransform>();
				textRectTransform.anchorMin = Vector2.zero;
				textRectTransform.anchorMax = Vector2.one;
				textRectTransform.sizeDelta = Vector2.zero;
				textRectTransform.offsetMin = new Vector2(10, 6);
				textRectTransform.offsetMax = new Vector2(-10, -7);
				
				RectTransform placeholderRectTransform = childPlaceholder.GetComponent<RectTransform>();
				placeholderRectTransform.anchorMin = Vector2.zero;
				placeholderRectTransform.anchorMax = Vector2.one;
				placeholderRectTransform.sizeDelta = Vector2.zero;
				placeholderRectTransform.offsetMin = new Vector2(10, 6);
				placeholderRectTransform.offsetMax = new Vector2(-10, -7);
				
				inputField.textComponent = text;
				inputField.placeholder = placeholder;
			}
			
			//[MenuItem("GameObject/UI/Canvas", false, 2009)]
			static public void AddCanvas(MenuCommand menuCommand)
			{
				var go = CreateNewUI();
				GameObjectUtility.SetParentAndAlign(go, menuCommand.context as GameObject);
				if (go.transform.parent as RectTransform)
				{
					RectTransform rect = go.transform as RectTransform;
					rect.anchorMin = Vector2.zero;
					rect.anchorMax = Vector2.one;
					rect.anchoredPosition = Vector2.zero;
					rect.sizeDelta = Vector2.zero;
				}
				Selection.activeGameObject = go;
			}
			
			static public GameObject CreateNewUI()
			{
				// Root for the UI
				var root = new GameObject("Canvas");
				root.layer = LayerMask.NameToLayer(kUILayerName);
				Canvas canvas = root.AddComponent<Canvas>();
				canvas.renderMode = RenderMode.ScreenSpaceOverlay;
				root.AddComponent<CanvasScaler>();
				root.AddComponent<GraphicRaycaster>();
				Undo.RegisterCreatedObjectUndo(root, "Create " + root.name);
				
				// if there is no event system add one...
				CreateEventSystem(false);
				return root;
			}
			
			//[MenuItem("GameObject/UI/EventSystem", false, 2010)]
			public static void CreateEventSystem(MenuCommand menuCommand)
			{
				GameObject parent = menuCommand.context as GameObject;
				CreateEventSystem(true, parent);
			}
			
			public static void CreateEventSystem(bool select)
			{
				CreateEventSystem(select, null);
			}
			
			public static void CreateEventSystem(bool select, GameObject parent)
			{
				var esys = Object.FindObjectOfType<EventSystem>();
				if (esys == null)
				{
					var eventSystem = new GameObject("EventSystem");
					GameObjectUtility.SetParentAndAlign(eventSystem, parent);
					esys = eventSystem.AddComponent<EventSystem>();
					eventSystem.AddComponent<StandaloneInputModule>();
					eventSystem.AddComponent<TouchInputModule>();
					
					Undo.RegisterCreatedObjectUndo(eventSystem, "Create " + eventSystem.name);
				}
				
				if (select && esys != null)
				{
					Selection.activeGameObject = esys.gameObject;
				}
			}
			
			// Helper function that returns a Canvas GameObject; preferably a parent of the selection, or other existing Canvas.
			static public GameObject GetOrCreateCanvasGameObject()
			{
				GameObject selectedGo = Selection.activeGameObject;
				
				// Try to find a gameobject that is the selected GO or one if its parents.
				Canvas canvas = (selectedGo != null) ? selectedGo.GetComponentInParent<Canvas>() : null;
				if (canvas != null && canvas.gameObject.activeInHierarchy)
					return canvas.gameObject;
				
				// No canvas in selection or its parents? Then use just any canvas..
				canvas = Object.FindObjectOfType(typeof(Canvas)) as Canvas;
				if (canvas != null && canvas.gameObject.activeInHierarchy)
					return canvas.gameObject;
				
				// No canvas in the scene at all? Then create a new one.
				return MenuOptions.CreateNewUI();
			}
		}
	//}


}
